package com.kasax.imgloader.v1.utils;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadExecutor {
    private static volatile ThreadExecutor instance;
    // 任务缓存
    private BlockingQueue<Future<?>> queue = new LinkedBlockingDeque<>();
    private final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();
    private final int MAXIMUM_POOL_SIZE = CORE_POOL_SIZE + 1;
    private final int KEEP_ALIVE_TIME = 60;
    private ThreadFactory threadFactory = new ThreadFactory() {
        AtomicInteger num = new AtomicInteger();

        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r, "Executor-" + num.incrementAndGet());
            return thread;
        }
    };

    private RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            try {
                queue.put(new FutureTask<>(r, null));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    private ThreadPoolExecutor threadPoolExecutor;

    // 工作线程
    private Runnable workRunnable = new Runnable() {
        @Override
        public void run() {
            while (true) {
                FutureTask<?> task = null;
                try {
                    task = (FutureTask<?>) queue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (task != null) {
                    threadPoolExecutor.execute(task);
                }
            }
        }
    };

    private ThreadExecutor() {
        threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4),
                threadFactory,
                rejectedExecutionHandler
        );
        threadPoolExecutor.execute(workRunnable);
    }

    public static ThreadExecutor getInstance() {
        if (instance == null) {
            synchronized (ThreadExecutor.class) {
                if (instance == null) {
                    instance = new ThreadExecutor();
                }
            }
        }
        return instance;
    }

    /**
     * 异步执行任务
     */
    public void enqueue(FutureTask<?> task) {
        if (task == null) {
            throw new NullPointerException("task == null");
        }
        try {
            queue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
